home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 February: Tool Chest / Dev.CD Feb 00 TC.toast / pc / what's new? / sample code / graphics 3d / opengl drawsprocket / opengl drawsprocket.c next >
Encoding:
C/C++ Source or Header  |  1999-11-25  |  19.1 KB  |  607 lines

  1. /*
  2.     File:        OpenGL DrawSprocket.cp
  3.  
  4.     Contains:    An example of OpenGL and DrawSprocket integration for full screen drawing.  
  5.                 Handles multiple displays and timing of swaps per second.
  6.                 
  7.                 The optimal way to select a rendering context would be to check the available devices, find the best,
  8.                 then present the user with a selction dialog only if there are more than one "best" device.
  9.                 Currently there is not a good mechanism to do this easily, so the two best other options are
  10.                 
  11.                 1) iterate throught the available devices find the best renderer, build a DSp context on this,
  12.                 then build your OpenGL context.  The downfall of this method is that you know nothing about the graphics
  13.                 capabilities of the device and the user can't select another screen.  The upside is that you get 
  14.                 a renderer that is has the capabilities you want.
  15.                 
  16.                 2) Allow the user to select a screen to use, build a DSp context and then a OpenGL context.  This
  17.                 second method is simpler but relies on user knowing which device is the best at 3D.
  18.                 
  19.                 This sample illustrates the second method which makes it simpler and allows us to illustrate the
  20.                 DSp/OpenGL interface well.                
  21.  
  22.     Written by:    Geoff Stahl
  23.                 original code by John Stauffer
  24.  
  25.     Copyright:    1999 Apple Computer, Inc., All Rights Reserved
  26.  
  27.     Change History (most recent first):
  28.  
  29.          <6>     11/24/99   GGS        Added better error checking, now all contexts built on window, put gl headers in system path, 
  30.                                      added agl font support, added averaged frame rate, cleaned up code
  31.          <6>     9/14/99    GGS        Corrected buffer rect handling and cleaned up code
  32.          <5>     7/14/99    GGS        Fixed multi-monitor window centering
  33.          <4>     7/13/99    GGS        Add work around for over zealous checking in single buffer DSp context attributes
  34.          <3>     7/5/99     GGS        Now correctly handle multi-monitor (DSp front buffer for single device; Window on top of context for multiple devices)
  35.          <2>     5/28/99    GGS     Added better multi-monitor support, clean code, corrected blanking bug, added timing, correct pixel formats
  36.          <1>        ?        ?      Initial build
  37.  
  38.     This code can be built for DrawSprocket 1.7.  Enable the #define kDSp17 below to add this.
  39.  
  40.       You may incorporate this sample code into your applications without
  41.       restriction, though the sample code has been provided "AS IS" and the
  42.       responsibility for its operation is 100% yours.  However, what you are
  43.       not permitted to do is to redistribute the source as "DSC Sample Code"
  44.       after having made changes. If you're going to re-distribute the source,
  45.      we require that you make it clear in the source that the code was
  46.     descended from Apple Sample Code, but that you've made changes.
  47.     
  48. */
  49.  
  50. // Building with DrawSprocket 1.7
  51. //#define kDSp17 1
  52.  
  53. #include <DrawSprocket.h>
  54. #include <DriverServices.h>
  55. #include <Files.h>
  56. #include <Folders.h>
  57. #include <Fonts.h>
  58. #include <Resources.h>
  59. #include <Sound.h>
  60. #include <TextUtils.h>
  61.  
  62. #include <math.h>
  63. #include <stdio.h>
  64. #include <string.h>
  65.  
  66. #include <agl.h>
  67. #include <aglRenderers.h>
  68. #include <gl.h>
  69.  
  70. //-----------------------------------------------------------------------------------------------------------------------
  71.  
  72. enum 
  73. {
  74.     kBitsPerPixel = 32,
  75.     kContextWidth = 400,
  76.     kContextHeight = 400
  77. };
  78.  
  79. // globals ---------------------------------------------------------------------------------------------------------------
  80.  
  81. const RGBColor    rgbBlack    = { 0x0000, 0x0000, 0x0000 };
  82.  
  83. NumVersion gVersionDSp;
  84. DSpContextAttributes gTheContextAttributes;
  85. DSpContextReference gTheContext;
  86. GDHandle ghGD;
  87. GLuint gFontList;
  88.  
  89.  
  90. // function prototypes ---------------------------------------------------------------------------------------------------
  91.  
  92. void CToPStr (StringPtr outString, const char *inString);
  93. void ReportError (char * strError);
  94. OSStatus DSpDebugStr (OSStatus error);
  95. GLenum aglDebugStr (void);
  96.  
  97. CGrafPtr SetupDSp (GDHandle *hGD, short *numDevices);
  98. void ShutdownDSp (CGrafPtr *ppWin);
  99.  
  100. AGLContext SetupAGL (GDHandle hGD, AGLDrawable win);
  101. void CleanupAGL (AGLContext ctx);
  102. void DrawGL (AGLContext ctx);
  103.  
  104. void DrawFrameRate (GLuint fontList);
  105.  
  106. void DrawPSringGL (Str255 pstrOut, GLuint fontList);
  107. void DrawCSringGL (char * cstrOut, GLuint fontList);
  108. GLuint BuildFontGL (AGLContext ctx, GLint fontID, Style face, GLint size);
  109. void DeleteFontGL (GLuint fontList);
  110.  
  111.  
  112. //-----------------------------------------------------------------------------------------------------------------------
  113.  
  114. // main: setup, draw loop, frames per swap timing, clean up (exit with mouse click)
  115.  
  116. int main(void)
  117. {
  118.     CGrafPtr pWin;
  119.     GDHandle hGD;
  120.     short numDevices = 0;
  121.     AGLContext ctx;
  122.     short fNum;
  123.     
  124.     // Mac Init
  125.     MaxApplZone ();
  126.     InitGraf(&qd.thePort);
  127.     InitFonts();
  128.     InitWindows();
  129.     InitMenus();
  130.     TEInit();
  131.     InitDialogs(nil);
  132.     InitCursor();
  133.             
  134.     pWin = SetupDSp (&hGD, &numDevices);                        // Setup DSp for OpenGL
  135.     if (!pWin) 
  136.         return 0;
  137.     ctx = SetupAGL(hGD, (AGLDrawable) pWin);                    // Setup the OpenGL context
  138.     if (!ctx) 
  139.         return 0;    
  140.     
  141.     GetFNum("\pMonaco", &fNum);                                    // build font
  142.     gFontList = BuildFontGL (ctx, fNum, normal, 9);
  143.  
  144.     do {        
  145.         DrawGL(ctx);                                            // OGL draw
  146.     } while (!Button());
  147.  
  148.     DeleteFontGL (gFontList);
  149.     CleanupAGL(ctx);                                            // Cleanup the OpenGL context
  150.     ShutdownDSp (&pWin);                                        // DSp shutdown
  151.     
  152.     FlushEvents(everyEvent, 0);
  153.     return 0;
  154. }
  155.  
  156. #pragma mark -
  157. //-----------------------------------------------------------------------------------------------------------------------
  158.  
  159. // Copy C string to Pascal string
  160.  
  161. void CToPStr (StringPtr outString, const char *inString)
  162. {    
  163.     unsigned char x = 0;
  164.     do
  165.         *(((char*)outString) + x) = *(inString + x++);
  166.     while ((*(inString + x) != 0)  && (x < 256));
  167.     *((char*)outString) = (char) x;                                    
  168. }
  169.  
  170. // --------------------------------------------------------------------------
  171.  
  172. void ReportError (char * strError)
  173. {
  174.     char errMsgCStr [256];
  175.     Str255 strErr;
  176.  
  177.     sprintf (errMsgCStr, "%s\n", strError); 
  178.  
  179.     // out as debug string
  180.     CToPStr (strErr, errMsgCStr);
  181.     DebugStr (strErr);
  182. }
  183.  
  184. //-----------------------------------------------------------------------------------------------------------------------
  185.  
  186. OSStatus DSpDebugStr (OSStatus error)
  187. {
  188.     switch (error)
  189.     {
  190.         case noErr:
  191.             break;
  192.         case kDSpNotInitializedErr:
  193.             ReportError ("DSp Error: Not initialized");
  194.             break;
  195.         case kDSpSystemSWTooOldErr:
  196.             ReportError ("DSp Error: system Software too old");
  197.             break;
  198.         case kDSpInvalidContextErr:
  199.             ReportError ("DSp Error: Invalid context");
  200.             break;
  201.         case kDSpInvalidAttributesErr:
  202.             ReportError ("DSp Error: Invalid attributes");
  203.             break;
  204.         case kDSpContextAlreadyReservedErr:
  205.             ReportError ("DSp Error: Context already reserved");
  206.             break;
  207.         case kDSpContextNotReservedErr:
  208.             ReportError ("DSp Error: Context not reserved");
  209.             break;
  210.         case kDSpContextNotFoundErr:
  211.             ReportError ("DSp Error: Context not found");
  212.             break;
  213.         case kDSpFrameRateNotReadyErr:
  214.             ReportError ("DSp Error: Frame rate not ready");
  215.             break;
  216.         case kDSpConfirmSwitchWarning:
  217. //            ReportError ("DSp Warning: Must confirm switch"); // removed since it is just a warning, add back for debugging
  218.             return 0; // don't want to fail on this warning
  219.             break;
  220.         case kDSpInternalErr:
  221.             ReportError ("DSp Error: Internal error");
  222.             break;
  223.         case kDSpStereoContextErr:
  224.             ReportError ("DSp Error: Stereo context");
  225.             break;
  226.     }
  227.     return error;
  228. }
  229.  
  230. //-----------------------------------------------------------------------------------------------------------------------
  231.  
  232. // if error dump agl errors to debugger string, return error
  233.  
  234. GLenum aglDebugStr (void)
  235. {
  236.     GLenum err = aglGetError();
  237.     if (AGL_NO_ERROR != err)
  238.         ReportError ((char *)aglErrorString(err));
  239.     return err;
  240. }
  241.  
  242. #pragma mark -
  243. //-----------------------------------------------------------------------------------------------------------------------
  244.  
  245. // Set up DSp screens, handles multi-monitor correctly
  246.  
  247. CGrafPtr SetupDSp (GDHandle *phGD, short *numDevices)
  248. {
  249.     OSStatus err = noErr;
  250.     GDHandle hDevice;
  251.     CGrafPtr pCGOut;
  252.     DSpContextAttributes foundAttributes;
  253.     DisplayIDType displayID;
  254.     Rect rectWin;
  255.     RGBColor rgbSave;
  256.     GrafPtr pGrafSave;
  257.     *numDevices = 0;
  258.  
  259.     // check for DSp
  260.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) 
  261.         ReportError ("DSp not installed");
  262.  
  263.     if (noErr != DSpDebugStr (DSpStartup()))
  264.         return NULL;
  265.  
  266. #ifdef kDSp17
  267.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpGetVersion) 
  268. #endif
  269.     {
  270.         // must be 1.1.4 or earlier so look at extension
  271.         short resFileSave, resFileDSp;
  272.         short vRefDSp;
  273.         long dirIDDSp;
  274.         FSSpec fsSpecDSp;
  275.         OSErr err;
  276.         Handle hVersion;
  277.         
  278.         // assume 1.0 version to start with (worst case)
  279.         gVersionDSp.majorRev = 1;
  280.         gVersionDSp.minorAndBugRev = 0;
  281.         gVersionDSp.stage = 0x80;
  282.         gVersionDSp.nonRelRev = 0;
  283.  
  284.         resFileSave = CurResFile();
  285.         SetResLoad (false);
  286.         // search application directory for debug lib
  287.         resFileDSp = OpenResFile ("\pDrawSprocketDebugLib");
  288.         err = ResError ();
  289.         if (fnfErr == err)
  290.         {
  291.             // search application directory for lib
  292.             resFileDSp = OpenResFile ("\pDrawSprocketLib");
  293.             err = ResError ();
  294.             if (fnfErr == err)
  295.             {
  296.                 // search extensions folder for debug lib
  297.                 FindFolder (kOnSystemDisk, kExtensionFolderType, kDontCreateFolder, &vRefDSp, &dirIDDSp);
  298.                 FSMakeFSSpec (vRefDSp, dirIDDSp, "\pDrawSprocketLib", &fsSpecDSp);
  299.                 resFileDSp = FSpOpenResFile (&fsSpecDSp, fsRdPerm);
  300.                 err = ResError ();
  301.                 if (fnfErr == err)
  302.                 {
  303.                     // search extensions folder directory for lib
  304.                     FSMakeFSSpec (vRefDSp, dirIDDSp, "\pDrawSprocketDebugLib", &fsSpecDSp);
  305.                     resFileDSp = FSpOpenResFile (&fsSpecDSp, fsRdPerm);
  306.                     err = ResError ();
  307.                 }
  308.             }
  309.         }
  310.         // if we have an open resource file and no error
  311.         if ((noErr == err) && (-1 != resFileDSp))
  312.         {
  313.             SetResLoad (true);
  314.             hVersion = GetResource ('vers', 1); 
  315.             err = ResError ();
  316.             if ((noErr == err) && (NULL != hVersion))
  317.             {
  318.                 gVersionDSp.majorRev = *(((unsigned char *)*hVersion) + 0);
  319.                 gVersionDSp.minorAndBugRev = *(((unsigned char *)*hVersion) + 1);
  320.                 gVersionDSp.stage = *(((unsigned char *)*hVersion) + 2);
  321.                 gVersionDSp.nonRelRev = *(((unsigned char *)*hVersion) + 3);
  322.                 ReleaseResource (hVersion);
  323.             }
  324.             UseResFile(resFileSave);
  325.             CloseResFile(resFileDSp);
  326.         }    
  327.     }
  328. #ifdef kDSp17
  329.     else
  330.         gVersionDSp = DSpGetVersion ();
  331. #endif
  332.  
  333.     hDevice = DMGetFirstScreenDevice (true);                                // check number of screens
  334.     do
  335.     {
  336.         (*numDevices)++;
  337.         hDevice = DMGetNextScreenDevice (hDevice, true);
  338.     }
  339.     while (hDevice);
  340.             
  341.     // Note: DSp < 1.7.3 REQUIRES the back buffer attributes even if only one buffer is required
  342.     memset(&gTheContextAttributes, 0, sizeof (DSpContextAttributes));
  343.     gTheContextAttributes.displayWidth            = kContextWidth;
  344.     gTheContextAttributes.displayHeight            = kContextHeight;
  345.     gTheContextAttributes.colorNeeds            = kDSpColorNeeds_Require;
  346.     gTheContextAttributes.displayBestDepth        = kBitsPerPixel;
  347.     gTheContextAttributes.backBufferBestDepth    = kBitsPerPixel;
  348.     gTheContextAttributes.displayDepthMask        = kDSpDepthMask_All;
  349.     gTheContextAttributes.backBufferDepthMask    = kDSpDepthMask_All;
  350.     gTheContextAttributes.pageCount                = 1;                                // only the front buffer is needed
  351.     
  352.     // will display user dialog if context selection is required otherwise as find best context
  353.     if (noErr != DSpDebugStr (DSpUserSelectContext(&gTheContextAttributes, 0L, nil, &gTheContext)))
  354.         return NULL;
  355.     if (noErr != DSpDebugStr (DSpContext_GetAttributes (gTheContext, &foundAttributes))) // see what we actually found
  356.         return NULL;
  357.         
  358.     // reset width and height to full screen and handle our own centering
  359.     // HWA will not correctly center less than full screen size contexts
  360.     gTheContextAttributes.displayWidth         = foundAttributes.displayWidth;
  361.     gTheContextAttributes.displayHeight     = foundAttributes.displayHeight;
  362.     gTheContextAttributes.pageCount            = 1;                                    // only the front buffer is needed
  363.     gTheContextAttributes.contextOptions    = 0 | kDSpContextOption_DontSyncVBL;    // no page flipping and no VBL sync needed
  364.  
  365.     DSpSetBlankingColor(&rgbBlack);
  366.     if (noErr !=  DSpDebugStr (DSpContext_GetDisplayID(gTheContext, &displayID)))     // get our device for future use
  367.         return NULL;
  368.     if (noErr !=  DMGetGDeviceByDisplayID(displayID, phGD, false))                     // get GDHandle for ID'd device
  369.     {
  370.         ReportError ("DMGetGDeviceByDisplayID() had an error.");
  371.         return NULL;
  372.     }
  373.     if (noErr !=  DSpDebugStr (DSpContext_Reserve ( gTheContext, &gTheContextAttributes))) // reserve our context
  374.         return NULL;
  375.  
  376.     HideCursor ();
  377.  
  378.     DSpDebugStr (DSpContext_FadeGammaOut (NULL, NULL));                             // fade display, remove for debug
  379.     if (noErr != DSpDebugStr (DSpContext_SetState (gTheContext, kDSpContextState_Active))) // activate our context
  380.         return NULL;
  381.     
  382.     // create a new window in our context 
  383.     // note: OpenGL is expecting a window so it can enumerate the devices it spans, 
  384.     // center window in our context's gdevice
  385.     rectWin.top  = (short) ((***phGD).gdRect.top + ((***phGD).gdRect.bottom - (***phGD).gdRect.top) / 2);          // h center
  386.     rectWin.top  -= (short) (kContextHeight / 2);
  387.     rectWin.left  = (short) ((***phGD).gdRect.left + ((***phGD).gdRect.right - (***phGD).gdRect.left) / 2);    // v center
  388.     rectWin.left  -= (short) (kContextWidth / 2);
  389.     rectWin.right = (short) (rectWin.left + kContextWidth);
  390.     rectWin.bottom = (short) (rectWin.top + kContextHeight);
  391.     
  392.     pCGOut = (CGrafPtr)NewCWindow (NULL, &rectWin, "\p", 0, plainDBox, (WindowPtr)-1, 0, 0);
  393.  
  394.     // paint back ground black before fade in to avoid white background flash
  395.     ShowWindow((GrafPtr)pCGOut);
  396.     GetPort (&pGrafSave);
  397.     SetPort ((GrafPtr)pCGOut);
  398.     GetForeColor (&rgbSave);
  399.     RGBForeColor (&rgbBlack);
  400.     PaintRect (&pCGOut->portRect);
  401.     RGBForeColor (&rgbSave);        // ensure color is reset for proper blitting
  402.     SetPort (pGrafSave);
  403.     
  404.     DSpDebugStr (DSpContext_FadeGammaIn (NULL, NULL));
  405.     
  406.     return pCGOut;
  407. }
  408.  
  409. //-----------------------------------------------------------------------------------------------------------------------
  410.  
  411. // clean up DSp
  412.  
  413. void ShutdownDSp (CGrafPtr *ppWin)
  414. {
  415.     DSpContext_FadeGammaOut (NULL, NULL);
  416.     if (*ppWin)
  417.         DisposeWindow ((WindowPtr)*ppWin);
  418.     *ppWin = NULL;
  419.     DSpContext_SetState( gTheContext, kDSpContextState_Inactive );
  420.     DSpContext_FadeGammaIn (NULL, NULL);
  421.     ShowCursor ();
  422.     DSpContext_Release (gTheContext);
  423.     DSpShutdown ();
  424. }
  425.  
  426. #pragma mark -
  427. //-----------------------------------------------------------------------------------------------------------------------
  428.  
  429. // OpenGL Setup
  430.  
  431. AGLContext SetupAGL (GDHandle hGD, AGLDrawable win)
  432. {
  433. // different possible pixel format choices for different renderers 
  434. // basics requirements are RGBA and double buffer
  435. // OpenGL will select acclerated context if available
  436.  
  437. // software renderer
  438. //    GLint          attrib[] = { AGL_RGBA, AGL_RENDERER_ID, AGL_RENDERER_GENERIC_ID, AGL_ALL_RENDERERS, AGL_DOUBLEBUFFER, AGL_NONE };
  439.  
  440. // any renderer
  441.     GLint          attrib[] = { AGL_RGBA, AGL_ALL_RENDERERS, AGL_DOUBLEBUFFER, AGL_NONE };
  442.  
  443. // OpenGL compliant HWA renderer 
  444. //    GLint          attrib[] = { AGL_RGBA, AGL_ACCELERATED, AGL_DOUBLEBUFFER, AGL_NONE };
  445.  
  446. // OpenGL compliant ATI renderer 
  447. //    GLint          attrib[] = { AGL_RGBA, AGL_RENDERER_ID, AGL_RENDERER_ATI_ID, AGL_DOUBLEBUFFER, AGL_NONE };
  448.  
  449. // OpenGL compliant ATI HWA renderer 
  450. //    GLint          attrib[] = { AGL_RGBA, AGL_RENDERER_ID, AGL_RENDERER_ATI_ID, AGL_ACCELERATED, AGL_DOUBLEBUFFER, AGL_NONE };
  451.  
  452.     AGLPixelFormat     fmt;
  453.     AGLContext         ctx;
  454.  
  455.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
  456.     {
  457.         ReportError ("OpenGL not installed\n");
  458.         return NULL;
  459.     }    
  460.  
  461.     if (hGD)                                                    // Choose an rgb pixel format use a device if we have one
  462.         fmt = aglChoosePixelFormat (&hGD, 1, attrib);             // get an appropriate pixel format
  463.     else
  464.         fmt = aglChoosePixelFormat(NULL, 0, attrib);            // get an appropriate pixel format
  465.     aglDebugStr ();
  466.     if (NULL == fmt) 
  467.     {
  468.         ReportError("Could not find valid pixel format\n");
  469.         return NULL;
  470.     }
  471.     
  472.     ctx = aglCreateContext (fmt, NULL);                            // Create an AGL context
  473.     aglDebugStr ();
  474.     if (NULL == ctx)
  475.     {
  476.         ReportError ("Could not create context\n");
  477.         return NULL;
  478.     }
  479.     
  480.     if (!aglSetDrawable (ctx, win))                                // attach the CGrafPtr to the context
  481.         aglDebugStr ();
  482.     else if (!aglSetCurrentContext (ctx))                        // make the context the current context
  483.     {
  484.         aglDebugStr ();
  485.         aglSetDrawable (ctx, NULL);
  486.     }
  487.  
  488.     aglDestroyPixelFormat(fmt);                                    // pixel format is no longer needed
  489.  
  490.     return ctx;
  491. }
  492.  
  493. //-----------------------------------------------------------------------------------------------------------------------
  494.  
  495. // OpenGL Cleanup
  496.  
  497. void CleanupAGL(AGLContext ctx)
  498. {
  499.     aglSetCurrentContext(NULL);
  500.     aglSetDrawable(ctx, NULL);
  501.     aglDestroyContext(ctx);
  502. }
  503.  
  504. //-----------------------------------------------------------------------------------------------------------------------
  505.  
  506. // OpenGL Drawing
  507.  
  508. void DrawGL(AGLContext ctx)
  509. {
  510.     static float f, s, c;
  511.     GLboolean fState = GL_FALSE;
  512.  
  513.     f += 0.01;
  514.     s = (float) sin(f);
  515.     c = (float) cos(f);
  516.  
  517.     glClearColor(0.15f, 0.15f, 0.15f, 1.0f);                    // Clear color buffer to dark grey
  518.     glClear(GL_COLOR_BUFFER_BIT);
  519.     
  520.     glBegin(GL_POLYGON);                                        // Draw a smooth shaded polygon
  521.     glColor3d(1.0, 0.0, 0.0);
  522.     glVertex3d(s, c, 0.0);
  523.     glColor3d(0.0, 1.0, 0.0);
  524.     glVertex3d(-c, s, 0.0);
  525.     glColor3d(0.0, 0.0, 1.0);
  526.     glVertex3d(-s, -c, 0.0);
  527.     glColor3d(0.7, 0.7, 0.7);
  528.     glVertex3d(c, -s, 0.0);
  529.     glEnd();
  530.     
  531.     // Draw frame rate (set color and position first)
  532.     glColor3d(1.0, 1.0, 1.0);
  533.     glRasterPos3d (-120.0 / (float) kContextWidth, (kContextHeight - 40.0) / (float) kContextHeight, 0.0); 
  534.     DrawFrameRate (gFontList);
  535.  
  536.     aglSwapBuffers(ctx);
  537. }
  538.  
  539. #pragma mark -
  540. //-----------------------------------------------------------------------------------------------------------------------
  541.  
  542. // Draw frame rate in curent color at current raster positon with provided font display list
  543.  
  544. void DrawFrameRate (GLuint fontList)
  545. {    
  546.     static char aChar[256] = "";
  547.     static AbsoluteTime time = {0,0};
  548.     static long frames = 0;
  549.  
  550.     AbsoluteTime currTime = UpTime ();
  551.     float deltaTime = (float) AbsoluteDeltaToDuration (currTime, time);
  552.     
  553.     frames++;
  554.  
  555.     if (0 > deltaTime)    // if negative microseconds
  556.         deltaTime /= -1000000.0;
  557.     else                // else milliseconds
  558.         deltaTime /= 1000.0;
  559.     if (0.5 <= deltaTime)    // has update interval passed
  560.     {
  561.         sprintf (aChar, "Swaps/Sec: %0.1f", frames / deltaTime);
  562.         time = currTime;    // reset for next time interval
  563.         frames = 0;
  564.     }
  565.     
  566.     DrawCSringGL (aChar, fontList);
  567. }
  568.  
  569. #pragma mark -
  570. //-----------------------------------------------------------------------------------------------------------------------
  571.  
  572. void DrawPSringGL (Str255 pstrOut, GLuint fontList)
  573. {
  574.     GLint i;
  575.     for (i = 1; i <= pstrOut[0]; i++)
  576.         glCallList (fontList + pstrOut[i]);
  577. }
  578.  
  579. //-----------------------------------------------------------------------------------------------------------------------
  580.  
  581. void DrawCSringGL (char * cstrOut, GLuint fontList)
  582. {
  583.     GLint i = 0;
  584.     while (cstrOut [i])
  585.         glCallList (fontList + cstrOut[i++]);
  586. }
  587.  
  588. //-----------------------------------------------------------------------------------------------------------------------
  589.  
  590. GLuint BuildFontGL (AGLContext ctx, GLint fontID, Style face, GLint size)
  591. {
  592.     GLuint listBase = glGenLists (256);
  593.     if (aglUseFont (ctx, fontID , face, size, 0, 256, (long) listBase))
  594.         return listBase;
  595.     else
  596.     {
  597.         glDeleteLists (listBase, 256);
  598.         return 0;
  599.     }
  600. }
  601.  
  602. //-----------------------------------------------------------------------------------------------------------------------
  603.  
  604. void DeleteFontGL (GLuint fontList)
  605. {
  606.     glDeleteLists (fontList, 256);
  607. }